package MySQL::Query::Extract;

use strict;
use warnings;

use base qw(MySQL::Query::Base);
__PACKAGE__->mk_accessors(qw( dbh tree tables ));

use Carp;
use Data::Dumper;
use SQL::Builder::Select;
use SQL::Builder::Table;

my $rule_class    = 'DBIx::MyParsePP::Rule';
my $token_class   = 'DBIx::MyParsePP::Token';
my @known_clauses = qw( SELECT FROM WHERE GROUPBY ORDERBY ); #SELECT ... FROM ... WHERE ... GROUPBY ORDERBY

sub parse_tree          { return shift->tree->tree }
sub known_clauses       { return wantarray ? @known_clauses : \@known_clauses }

sub init {
      my $self = shift;
      croak "No tree passed to constructor" unless $self->tree;
      #croak "No tables2" unless $self->tables;
}

sub extract_one {
      my $self = shift;
      my $table_or_alias = shift;
      die "extract_one expects only one table or alias"
            if (@_);
      return $self->_extract([$table_or_alias]);
}

sub extract_all {
      my $self = shift;
      die "extract_all doesn't expect any params"
            if (@_);
      my $uniq = $self->tables->uniq; # getting tables and aliases
      return $self->_extract($uniq);
}

sub extract_many {
      my ($self , $extract) = @_;
      die "extract_many expects arrayref, if you want to extract only one table, use extract_one"
            unless (ref $extract eq 'ARRAY');
      return $self->_extract($extract);
}

sub _extract {
      my ($self , $extract) = @_;
      
      my $sel = SQL::Builder::Select->new();
      
      foreach my $clause ($self->known_clauses()) {
	    my $clause_class = "MySQL::Query::Extract::$clause";
	    eval qq{ require $clause_class; 1; # load the clause parsing module } or die $@;
	    my $method = $clause_class->new( tree => $self->tree , tables => $self->tables );
	    $method->process($sel , $extract);
      }
      
      return $sel;  
}

# the methods below should be re-designed

sub extract_many_with_known_conds {
      my ($self , $tables , $aliases) = @_;
      
      my $sel = $self->extract_many($tables , $aliases);
      $sel->where->list_clear;
      
      return $self->known_conditions($tables , $aliases , $sel);
}

sub known_conditions {
      my ($self , $table , $alias , $sel) = @_;
      
      unless ($sel) {
	    $sel = SQL::Builder::Select->new();
	
	    # add table which we recived
	    my $sel_table = SQL::Builder::Table->new();
	    $sel_table->name($table);
	    $sel_table->alias($alias->[0]);
	    $sel->tables->list_push( $sel_table );
      }
      
      my $clause_class = "MySQL::Query::Extract::WHERE";
      eval qq{ require $clause_class;	# load the clause parsing module };
      my $clause = $clause_class->new( tree => $self->tree );
      $clause->process($sel , $table , $alias , "known_cond");
      
      return $sel;
}

sub unknown_conditions {
      my ($self , $table , $alias) = @_;
      
      my $clause_class = "MySQL::Query::Extract::WHERE";
      eval qq{ require $clause_class;	# load the clause parsing module };
      my $clause = $clause_class->new( tree => $self->tree );
      return $clause->unknown_conditions($table , $alias , 0);
}

#-----------------------------------------
#-----------------------------------------
#-----------------------------------------

sub cmp_names {
      my ($self , $cmp , $tables) = @_;
      
      return 0 unless $cmp;
      $tables = [$tables] unless ref $tables eq 'ARRAY';
      
      return 1 if grep { $_ eq $cmp } @$tables;
      
      return 0;
}

sub exact_match {
      my ($self , $cmp , $tables , $aliases) = @_;
      
      return 0 unless $cmp;
      
      my $ok = 0;
      
      if ($tables) {
            $tables = [$tables] unless ref $tables eq 'ARRAY';
            $ok++ if grep { $_ eq $cmp } @$tables;
      }
      if ($ok and $aliases) {
            $aliases = [$aliases] unless ref $aliases eq 'ARRAY';
            return 1 if grep { $_ eq $cmp if $_ } @$aliases;
      } elsif ($ok and !$aliases) {
            return 1;
      }
}

sub col_has_alias {
      my ($self , $data) = @_;
      return unless ref $data eq $rule_class;
      if ($data->name() eq 'select_alias') {
	    return $data->[2]->value();
      }
}

sub check_arrays_cnt {
      my ($self , $first, $second) = @_;
      for my $f (@$first) {
	    return 0 unless grep { $f eq $_ } @$second;
      }
      return 1;
}  

sub alias_list {
      my ($self , $alias) = @_;
      my @aliases_list;
      
      if (ref $alias eq 'ARRAY' and
          $alias->[0] and
          ref $alias->[0] eq 'ARRAY'
      ) {
            @aliases_list = map { @$_ if $_ } @$alias;
      } elsif (ref $alias eq 'ARRAY') {
            push @aliases_list , @$alias;
      } else {
            push @aliases_list , $alias;
      }
      return \@aliases_list;
}

sub get_table_alias {
      my ($self , $table , $ignore) = @_;
      
      #use Data::Dumper;
      #print Dumper $table;
      #print Dumper $self;
      return unless $table;
      my $alias = $self->{tables}->alias($table);
      #print $table , " -> " , Dumper $alias;
      if ($alias) {
            while (my $a = $alias->next) {
                  return $a unless grep { $a eq $_ } @$ignore;
            }
            
      }
}


1;

=head1 NAME

MySQL::Query::Extract

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 METHODS

=head2 new()

=head2 extract()

=head2 known_conditions()

=head2 unknown_conditions()
